package io.github.shenbinglife.springboot2.layui.admin.service.impl;

import io.github.shenbinglife.springboot2.layui.admin.dao.UserDao;
import io.github.shenbinglife.springboot2.layui.admin.entity.Org;
import io.github.shenbinglife.springboot2.layui.admin.entity.Role;
import io.github.shenbinglife.springboot2.layui.admin.entity.User;
import io.github.shenbinglife.springboot2.layui.admin.model.UserDetail;
import io.github.shenbinglife.springboot2.layui.common.service.impl.BaseService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.transaction.Transactional;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Transactional
@Service
public class UserService extends BaseService<User, UserDao> {

    @Autowired
    private OrgService orgDao;

    @Autowired
    private RoleService roleDao;

    public Page<User> page(String keyword, String name,
                           String orgName,
                           String roleName,
                           String orgId,
                           String roleId,
                           String notOrgId,
                           String notRoleId,
                           String mobilePhone,
                           int pageNo,
                           int pageSize) {
        Sort sorter = Sort.by(Sort.Direction.DESC, "updateTime");
        PageRequest pageRequest = PageRequest.of(pageNo, pageSize, sorter);
        Page<User> pageUsers = baseDao.findUsersWithPagination(keyword, name,
                orgName,
                roleName,
                orgId,
                roleId,
                notOrgId,
                notRoleId,
                mobilePhone, pageRequest);
        return pageUsers;
    }

    public void deleteUsers(Long[] userIds) {
        if (userIds == null) {
            return;
        }
        for (Long userId : userIds) {
            this.deleteById(userId);
        }
    }

    @Override
    public void deleteById(Long id) {
        roleDao.removeRelationByUserId(id);
        orgDao.removeRelationByUserId(id);
        super.deleteById(id);
    }

    public void updateState(Long id, User.UserState state) {
        baseDao.updateStateById(id, state);
    }

    public UserDetail createUser(UserDetail userDetail) {
        User user = new User();
        BeanUtils.copyProperties(userDetail, user, User.class);
        User save = baseDao.save(user);
        baseDao.updatePassword(save.getId(), DigestUtils.md5DigestAsHex(User.DEFAULT_PWD.getBytes(StandardCharsets.UTF_8)));
        for (Long orgId : userDetail.getOrgIds()) {
            orgDao.addUserToOrg(orgId, save.getId());
        }

        for (Long roleId : userDetail.getRoleIds()) {
            roleDao.addUsersToRole(roleId, save.getId());
        }

        return getUserDetail(save.getId());
    }

    public UserDetail getUserDetail(Long id) {
        User user = baseDao.getOne(id);
        if (user == null) {
            throw new RuntimeException("User not found by id: " + id);
        }
        UserDetail userDetail = new UserDetail();
        BeanUtils.copyProperties(user, userDetail);
        List<Long> roleIds = roleDao.getUserRoles(user.getId())
                .stream()
                .map(Role::getId)
                .collect(Collectors.toList());
        userDetail.setRoleIds(roleIds);

        List<Long> orgIds = orgDao.getUserOrgs(user.getId())
                .stream()
                .map(Org::getId)
                .collect(Collectors.toList());
        userDetail.setOrgIds(orgIds);
        return userDetail;
    }

    public void updateUser(UserDetail userDetail) {
        User u = new User();
        BeanUtils.copyProperties(userDetail, u, User.class);
        baseDao.save(u);
    }

    public void updatePassword(Long id, String password) {
        baseDao.updatePassword(id, password);
    }

    public Boolean login(String account, String password) {
        User user = baseDao.findByAccount(account);
        if (user == null) {
            return false;
        }
        String passwordOfUser = baseDao.getPasswordByUserId(user.getId());
        return Objects.equals(passwordOfUser, password);
    }

    public void resetPassword(Long... userIds) {
        for (Long userId : userIds) {
            updatePassword(userId, DigestUtils.md5DigestAsHex(User.DEFAULT_PWD.getBytes(StandardCharsets.UTF_8)));
        }
    }

    public User getByAccount(String account) {
        return baseDao.findByAccount(account);
    }
}
